#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#include "../src/estep.c"

typedef struct _EstepTestDatum EstepTestDatum ;
struct _EstepTestDatum 
{ 
  struct
    {
      double    priorz[5];
      Rating    ratings[8];
      double    logalpha[3];
      double    tau[4*(5-1)];
      int       clamp[3];
    }                   inputs;

  double pz[3*5];
};

static void
test_estep (void)
{
  EstepTestDatum data[] = 
    {{{{0.126306, 0.662226, 0.75918, 0.201118,  0.641774}, {{1, 0, 1}, {2, 1, 3}, {3, 1, 3}, {0, 0, 4}, {0, 2,  3}, {2, 2, 3}, {0, 2, 2}, {2, 0, 2}}, {0.371336, 0.251341,  0.266777}, {0.760851, 0.524434, 0.462094, 0.595622, 0.898279,  0.661029, 0.404984, 0.00675358, 0.0990124, 0.344021, 0.838477,  0.466829, 0.135226, 0.642028, 0.908986, 0.410885}, {-1,  1, -1}}, {0.0369745, 0.959665, 0.00336008, 8.12296e-7,  1.94642e-9, 1.7034e-7, 0.999999, 6.67966e-7,  6.47646e-8, 5.23976e-9, 0.00942064, 0.955016, 0.035489,  0.0000733131,  1.38338e-6}}, {{{0.209767, 0.367147, 0.608465, 0.898466,  0.94299}, {{2, 2, 2}, {1, 1, 3}, {3, 2, 3}, {3, 2, 2}, {2, 2,  1}, {3, 2, 2}, {3, 2, 0}, {2, 1, 4}}, {0.606295, 0.0840318,  0.436371}, {0.347368, 0.708016, 0.423003, 0.0313873, 0.340614,  0.609004, 0.0789819, 0.19291, 0.873785, 0.473778, 0.436954,  0.283924, 0.4629, 0.464857, 0.457152, 0.134118}, {-1, -1,  0}}, {0.0693024, 0.121297, 0.201024, 0.296833, 0.311543,  0.00911138, 0.280156, 0.382868, 0.237798, 0.0900674, 1.,  2.04537e-8, 5.94572e-17, 3.17587e-26,  1.32521e-35}}, {{{0.235652, 0.310143, 0.491415, 0.764655,  0.799281}, {{0, 2, 1}, {0, 0, 4}, {1, 0, 2}, {0, 1, 2}, {3, 1,  4}, {1, 2, 1}, {1, 1, 3}, {0, 1, 3}}, {0.962776, 0.783399,  0.341652}, {0.767894, 0.622162, 0.174395, 0.26267, 0.574983,  0.748377, 0.700617, 0.825716, 0.291059, 0.285477, 0.23576,  0.368564, 0.156941, 0.0323438, 0.138049, 0.519877}, {2, 1,  4}}, {3.01495e-7, 0.000200544, 0.999799, 1.40001e-8,  7.46452e-11, 1.24784e-9, 1., 1.72675e-9, 3.14297e-13,  5.03232e-17, 0.911945, 0.0879898, 0.0000634325, 1.71326e-8,  1.55451e-6}}, {{{0.755223, 0.122008, 0.759424, 0.863236,  0.41357}, {{0, 1, 4}, {0, 2, 4}, {1, 0, 0}, {0, 0, 3}, {3, 2,  2}, {1, 0, 2}, {0, 0, 3}, {1, 1, 1}}, {0.354114, 0.137263,  0.688841}, {0.1509, 0.779131, 0.388886, 0.988224, 0.325184,  0.488072, 0.103409, 0.752464, 0.956619, 0.331131, 0.0710648,  0.614414, 0.436742, 0.409842, 0.348864, 0.96778}, {3, -1,  0}}, {0.556194, 0.44315, 0.0000709695, 0.000585043,  1.89898e-14, 0.540517, 0.254296, 0.194607, 0.0104005,  0.000179872, 0.99978, 0.000202691, 0.0000167303, 3.88321e-7,  7.4611e-9}}, {{{0.104545, 0.267949, 0.933721, 0.452177,  0.415704}, {{1, 1, 4}, {0, 0, 3}, {2, 0, 0}, {2, 1, 1}, {0, 2,  1}, {3, 2, 3}, {0, 0, 1}, {2, 1, 1}}, {0.117049, 0.15459,  0.0632918}, {0.42748, 0.791865, 0.666518, 0.959883, 0.675016,  0.835246, 0.335387, 0.888818, 0.0606014, 0.398504, 0.925545,  0.539954, 0.0928212, 0.716985, 0.63771, 0.950514}, {4, -1,  1}}, {0.791958, 0.207733, 0.000304639, 7.1288e-8,  4.27011e-6, 0.190858, 0.787873, 0.0212532, 0.0000155844,  1.50293e-8, 1.36623e-6, 0.999998, 1.938e-7, 4.43381e-9,  7.29409e-11}}, {{{0.498337, 0.572573, 0.331987, 0.5494,  0.435045}, {{0, 1, 4}, {0, 2, 3}, {2, 0, 2}, {1, 0, 1}, {3, 1,  4}, {0, 0, 3}, {3, 0, 0}, {0, 0, 0}}, {0.145093, 0.540122,  0.882881}, {0.475162, 0.470077, 0.704876, 0.547494, 0.586343,  0.409476, 0.306371, 0.62195, 0.0463893, 0.316655, 0.589386,  0.98424, 0.0958752, 0.328378, 0.14035, 0.28025}, {4, 0,  2}}, {0.994236, 0.00576379, 1.09218e-8, 2.21311e-15,  1.03825e-16, 0.992493, 0.000889814, 0.00202314, 0.00227414,  0.0023203, 1.10855e-6, 0.000018577, 0.99998, 2.29112e-7,  2.04664e-8}}, {{{0.730851, 0.162494, 0.610712, 0.268241,  0.847969}, {{2, 0, 0}, {0, 0, 2}, {3, 0, 3}, {2, 1, 3}, {0, 1,  4}, {2, 2, 1}, {1, 2, 4}, {2, 2, 2}}, {0.687332, 0.140635,  0.563365}, {0.300475, 0.100989, 0.731159, 0.256994, 0.678525,  0.0545994, 0.414505, 0.667607, 0.694286, 0.958724, 0.0861265,  0.527257, 0.414035, 0.361186, 0.330321, 0.718895}, {2, -1,  1}}, {0.874842, 0.057731, 0.0674267, 1.75286e-13,  1.6116e-19, 0.0289239, 0.173361, 0.583051, 0.103513, 0.111151,  3.30323e-7, 1., 1.48333e-9, 2.79396e-13,  4.43803e-17}}, {{{0.450654, 0.835215, 0.51136, 0.578974,  0.887289}, {{2, 2, 0}, {1, 0, 4}, {0, 2, 0}, {2, 2, 3}, {1, 2,  2}, {2, 1, 0}, {2, 2, 0}, {1, 2, 3}}, {0.534741, 0.410371,  0.847815}, {0.630295, 0.856215, 0.355772, 0.433311, 0.962688,  0.16193, 0.397048, 0.347184, 0.43543, 0.747894, 0.035862,  0.0168629, 0.716536, 0.0647098, 0.83717,  0.297254}, {-1, -1, -1}}, {0.00508026, 0.221994, 0.191648,  0.22829, 0.352988, 0.958535, 0.0413879, 0.0000771246,  2.18902e-7, 8.14459e-10, 0.999998, 1.72578e-6,  1.84224e-22, 1.36709e-38,  1.26721e-54}}, {{{0.718279, 0.378593, 0.694754, 0.915439,  0.870464}, {{2, 0, 2}, {0, 0, 2}, {1, 1, 1}, {2, 2, 1}, {3, 2,  4}, {3, 0, 4}, {2, 1, 2}, {3, 0, 3}}, {0.748298, 0.838539,  0.559667}, {0.437153, 0.785611, 0.676609, 0.16262, 0.0899687,  0.35018, 0.928714, 0.126758, 0.0731058, 0.633644, 0.864004,  0.289588, 0.775852, 0.367762, 0.63451, 0.963777}, {-1, 0,  4}}, {0.000392407, 0.999155, 0.000453047, 1.9576e-8,  4.93393e-13, 1., 1.45989e-7, 2.39032e-12, 2.34139e-17,  2.22921e-22, 0.0609329, 0.735465, 0.0139024, 0.000087617,  0.189612}}, {{{0.0483385, 0.187109, 0.24087, 0.101218,  0.488671}, {{1, 0, 1}, {0, 2, 4}, {1, 1, 0}, {0, 1, 0}, {2, 1,  0}, {2, 1, 4}, {2, 1, 4}, {2, 1, 4}}, {0.749956, 0.45526,  0.424609}, {0.326052, 0.659988, 0.10508, 0.495895, 0.199294,  0.586882, 0.471435, 0.63189, 0.909706, 0.81103, 0.103673, 0.99738,  0.945929, 0.753457, 0.114505, 0.0576239}, {3, 4, 4}}, {0.750296,  0.0821488, 0.000228139, 0.167327, 7.34466e-10, 0.100994,  0.899006, 2.85106e-7, 3.82098e-15, 1.09817e-17,  1.05378e-7, 1.49922e-6, 2.26989e-6, 2.45774e-6,  0.999994}}};


  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      double pz[3*5];

      for (unsigned int j = 0; j < 3*5; ++j) { pz[j] = drand48 (); }

      estep (data[i].inputs.logalpha,
             5,
             data[i].inputs.tau,
             3,
             pz,
             data[i].inputs.priorz,
             data[i].inputs.clamp,
             data[i].inputs.ratings,
             8);

      for (unsigned int j = 0; j < 3*5; ++j)
        {
          assert (fabs (pz[j] - data[i].pz[j]) <=
                  1e-4 * (1 + fabs (pz[j]) + fabs (data[i].pz[j])) ||
                  (fprintf (stderr, "%u: %g ?= %g\n", j, pz[j], data[i].pz[j]), 0));
        }
    }
}

int 
main (void)
{
  srand48 (69);

  test_estep ();

  return 0;
}
